﻿using System;
using System.Collections.Generic;
using System.Text;
using CeA.Reports.Atendimento.DataAccess.DTO;
using IBatisNet.DataMapper;
using CeA.Reports.Atendimento.DataAccess.Helpers;
using System.Security.Authentication;
using CeA.Reports.Atendimento.DataAccess.Criteria;

namespace CeA.Reports.Atendimento.DataAccess.DAO.Oracle {
    public class OracleUsuarioImpl: Usuario {

        public UsuarioDTO Autenticar(LoginDTO login)                {
            login.Senha = AuthenticationHelper.CalcularHashSenha(login.Senha);

            UsuarioDTO dto = Mapper.Instance().QueryForObject<UsuarioDTO>("authenticateUser", login);
            
            if(dto == null)
                throw new AuthenticationException("Usuário ou senha invalidos.");

            if (dto.ContaBloqueada == "S")
                throw new AuthenticationException("Sua conta está bloqueada. Acione o suporte técnico.");

            login.Senha = "********";

            dto.addRole(RecuperarRoles(dto.Id));

            return dto;
        }


        public List<UsuarioDTO> Listar(UsuarioCriteria criteria)    {
            IList<UsuarioDTO> list = Mapper.Instance().QueryForList<UsuarioDTO>("listAll", criteria);
            return (List<UsuarioDTO>)list;
        }


        public UsuarioDTO Recuperar(int id)                         {
            UsuarioDTO dto = Mapper.Instance().QueryForObject<UsuarioDTO>("getUsuarioById", id);

            dto.addRole(RecuperarRoles(dto.Id));

            return dto;
        }


        public UsuarioDTO Recuperar(string login)                   {
            UsuarioDTO dto = Mapper.Instance().QueryForObject<UsuarioDTO>("getUsuarioByLogin", login);
            
            List<RoleDTO> roles = RecuperarRoles(dto.Id);
            for (int i = 0; i < roles.Count; i++)
                dto.addRole(roles[i]);

            return dto;
        }


        public List<RoleDTO> RecuperarRoles()                       {
            IList<RoleDTO> list = Mapper.Instance().QueryForList<RoleDTO>("listAllRoles", 1);
            return (List<RoleDTO>)list;
        }


        public List<RoleDTO> RecuperarRoles(int id)                 {
            IList<RoleDTO> list = Mapper.Instance().QueryForList<RoleDTO>("loadUserRolesById", id);
            return (List<RoleDTO>)list;
        }


        public List<RoleDTO> RecuperarRoles(string login)           {
            IList<RoleDTO> list = Mapper.Instance().QueryForList<RoleDTO>("loadUserRolesByLogin", login);
            return (List<RoleDTO>)list;
        }


        public UsuarioDTO Salvar(UsuarioDTO usuario)                {
            ISqlMapper mapper = Mapper.Instance();

            if (checkForExistingLogin(usuario))
                throw new InvalidOperationException("O login informado já existe. Tente outro login");

           
            if (usuario.Senha.Trim().Length > 0)
                usuario.Senha = AuthenticationHelper.CalcularHashSenha(usuario.Senha);
           

            // Inicia a inclusão dos dados do usuário
            try {
                mapper.BeginTransaction();

                usuario.Id = (int)mapper.Insert("insertUser", usuario);
                mapper.Insert("insertUserDetails", usuario);


                // Adiciona as Roles do Usuário
                UsuarioRoleDTO usuarioRole = new UsuarioRoleDTO();
                foreach (RoleDTO role in usuario.Roles) {
                    usuarioRole.UsuarioId = usuario.Id;
                    usuarioRole.RoleId = role.Id;
                    mapper.Insert("insertUserRole", usuarioRole);
                }

                usuario.Senha = "********";

                mapper.CommitTransaction();
            }
            catch(Exception ex) {
                mapper.RollBackTransaction();
                throw ex;
            }
            
            return usuario;
        }


        public UsuarioDTO Atualizar(UsuarioDTO usuario)             {
            ISqlMapper mapper = Mapper.Instance();

            if (usuario.Senha.Trim().Length > 0)
                usuario.Senha = AuthenticationHelper.CalcularHashSenha(usuario.Senha);


            if (usuario.Id == 1 && usuario.ContaBloqueada == "S")
                throw new InvalidOperationException("Não é possível desativar a conta do super-usuário (admin)!");


            try {
                mapper.BeginTransaction();

                // Inicia a atualizacao dos dados do usuário
                mapper.Update("updateUser", usuario);
                mapper.Update("updateUserDetails", usuario);
                mapper.Delete("deleteUserRoles", usuario);


                // Adiciona as Roles do Usuário
                UsuarioRoleDTO usuarioRole = new UsuarioRoleDTO();
                foreach (RoleDTO role in usuario.Roles) {
                    usuarioRole.UsuarioId = usuario.Id;
                    usuarioRole.RoleId = role.Id;
                    mapper.Insert("insertUserRole", usuarioRole);
                }

                mapper.CommitTransaction();
            }
            catch (Exception ex) {
                mapper.RollBackTransaction();
                throw ex;
            }

            return usuario;
        }


        public void Desativar(int id)                               {
            if(id == 1)
                throw new InvalidOperationException("Não é possível desativar a conta do super-usuário (admin)!");

            Mapper.Instance().Delete("disableUserAccount", id);
        }


        private bool checkForExistingLogin(UsuarioDTO usuario)      {
            int count = Mapper.Instance().QueryForObject<int>("checkForExistingLogin", usuario);
            return (count > 0);
        }
    }
}
